import type { Ref } from "vue";
import { unref, onUnmounted, onDeactivated, watch, isRef } from 'vue'
import { onMountedOrActivated } from "./onMountedOrActivated";

type TargetRef = EventTarget | Ref<EventTarget>
export type UseEventListenerOptions = {
    target?: TargetRef // window, document, Element都是EventTarget对象，一些非节点元素也是EventTarget，比如Ajax中的XMLHttpRequest对象
    capture?: boolean // 设置事件捕获方式，默认为false，不使用捕获，事件使用冒泡机制；设置为true，使用捕获机制
    passive?: boolean // EventListener内部是否可以使用event.preventDefault()，设置为true的时候将不能使用，否则会提示错误信息： Unable to preventDefault inside passive event listener invocation.
}

export function useEventListener<K extends keyof DocumentEventMap>(
    type: K,
    listener: EventListener,
    options: UseEventListenerOptions = {}
) {
    const { target = window, passive = false, capture = false } = options

    /**
     * 添加事件监听
     */
    const add = (target: TargetRef) => {
        const element = unref(target)
        if (element) {
            element.addEventListener(type, listener, {
                passive,
                capture
            })
        }
    }

    /**
     * 取消事件监听
     */
    const remove = (target: TargetRef) => {
        const element = unref(target)
        if (element) {
            element.removeEventListener(type, listener, capture)
        }
    }

    onMountedOrActivated(() => add(target))

    onUnmounted(() => remove(target))

    onDeactivated(() => remove(target))

    // 如果target是个响应式的，监听其是否有变化，有变化则移除旧的事件监听，增加新的事件监听
    if (isRef(target)) {
        watch(target, (nv: TargetRef, ov: TargetRef) => {
            remove(ov)
            add(nv)
        })
    }
}